package com.ryan.mdp.config;

import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedSet;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

public abstract class AbstractMdpBeanDefinationParser extends AbstractSingleBeanDefinitionParser {

    protected static final String INTERFACE_ATTRIBUTE = "interface";

    protected static final String DESTINATION_ATTRIBUTE = "destination";

    protected static final String DESTINATION_TYPE_ATTRIBUTE = "destination-type";

    protected static final String CONCURRENCY_ATTRIBUTE = "concurrency";

    protected static final String CONNECTION_FACTORY_ATTRIBUTE = "connection-factory";

    protected static final String TTL_ATTRIBUTE = "ttl";

    protected static final String DESTINATION_TYPE_QUEUE = "queue";

    protected static final String DESTINATION_TYPE_TOPIC = "topic";

    protected static final String DESTINATIONS = "destinations";

    protected static final String INTERFACES = "interfaces";

    /**
     * 消费消息时是否开启事务，true时发生异常时消息回滚，false时发生异常不回滚
     */
    private static final String TRANSACTED_ATTRIBUTE = "transacted";

    @Override
    protected boolean shouldGenerateIdAsFallback() {
        return true;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
        // mdp:interface attribute
        String interfaceAttr = element.getAttribute(INTERFACE_ATTRIBUTE);
        if (!"".equals(interfaceAttr)) {
            builder.addPropertyValue("interfaze", interfaceAttr);
        }
        // mdp:destination attribute
        String destinationAttr = element.getAttribute(DESTINATION_ATTRIBUTE);
        if (!"".equals(destinationAttr)) {
            ManagedSet set = new ManagedSet(1);
            set.setMergeEnabled(false);
            set.setSource(element);
            set.add(destinationAttr);
            builder.addPropertyValue("destinations", set);
        }
        // mdp:destination-type attribute
        String destinationTypeAttr = element.getAttribute(DESTINATION_TYPE_ATTRIBUTE);
        if ("".equals(destinationTypeAttr) || DESTINATION_TYPE_QUEUE.equals(destinationTypeAttr)) {
            builder.addPropertyValue("pubSubDomain", false);
        } else if (DESTINATION_TYPE_TOPIC.equals(destinationTypeAttr)) {
            builder.addPropertyValue("pubSubDomain", true);
        } else {
            parserContext.getReaderContext().error(
                    "'destination-type' attribute is neithor 'queue', nor 'topic', or default empty", element);
        }
        // mdp:concurrency attribute
        String concurrency = element.getAttribute(CONCURRENCY_ATTRIBUTE);
        if (!"".equals(concurrency)) {
            builder.addPropertyValue("concurrency", concurrency);
        }
        // server: transacted attribute
        String transacted = element.getAttribute(TRANSACTED_ATTRIBUTE);
        if (!"".equals(transacted)) {
            builder.addPropertyValue(TRANSACTED_ATTRIBUTE, Boolean.valueOf(transacted));
        }
        // mdp:ttl attribute
        String ttl = element.getAttribute(TTL_ATTRIBUTE);
        if (!"".equals(ttl)) {
            builder.addPropertyValue("ttl", ttl);
        }
        // mdp:connection-factory
        String connectionFactoryBeanName = "connectionFactory";
        if (element.hasAttribute(CONNECTION_FACTORY_ATTRIBUTE)) {
            connectionFactoryBeanName = element.getAttribute(CONNECTION_FACTORY_ATTRIBUTE);
            if (!StringUtils.hasText(connectionFactoryBeanName)) {
                parserContext.getReaderContext().error(
                        "mdp service 'connection-factory' attribute contains empty value.", element);
            }
        }
        builder.addPropertyValue("connectionFactory", new RuntimeBeanReference(connectionFactoryBeanName));

        doParseSpecial(element, parserContext, builder);
    }

    /**
     * 解析service和reference特有的配置项
     * 
     * @param element
     * @param builder
     */
    protected abstract void doParseSpecial(Element element, ParserContext parserContext, BeanDefinitionBuilder builder);

}
